#pragma once
#include "log.hpp"
#include "Socket.hpp"
#include "HttpRequest.hpp"
#include <thread>
#include <iostream>
#include <fstream>
#include <unordered_map>

#define PORT 9000

class HttpServer
{
public:
    HttpServer(uint16_t port = PORT) : _port(port)
    {
        _contentType.insert({".html", "text/html"});
        _contentType.insert({".png", "image/png"});
        _contentType.insert({".jpg", "image/jpeg"});
    }

    void startServer()
    {
        _sock.Socket();
        _sock.Bind(_port);
        _sock.Listen();
        // log(INFO, "here\n");
        for (;;) {
            string clientIp;
            uint16_t clientPort;
            int sockFd = _sock.Accept(&clientIp, &clientPort);
            log(INFO, "get a new link, fd: %d\n", sockFd);
            thread([=]
            {
                handlerHttp(sockFd);
            }).detach();
        }
    }

    // 获得请求，发送响应
    void handlerHttp(int sockFd)
    {
        char buf[10240];
        memset(buf, 0, sizeof buf);
        for(;;) {
            ssize_t n = read(sockFd, buf, sizeof buf);
            if (n > 0) {
                // 打印一下客户端的信息
                buf[n] = 0;
                cout << buf;
                // 自定义协议，获取路径
                HttpRequest req = HttpRequest();
                req.deserialize(buf);
                req.parseHeadLine();
                // 返回响应
                string text = "";
                string statusLine = "";
                string exitStr = readFromFile(req.filePath);
                if(exitStr.empty()) {
                    statusLine = "HTTP/1.1 404 Not Found\r\n";
                    // 从出错页面读取
                    string path = ROOTPATH;
                    path += "/404Page.html";
                    text = readFromFile(path);
                } else {
                    // 正常读取
                    statusLine = "HTTP/1.1 200 OK\r\n";
                    text = exitStr;
                }

                string header = "Content-Length: ";
                header += to_string(text.size()) + "\r\n";
                header += "Content-Type: ";
                header += getContentTypeValue(req.suffix) + "\r\n";
                header += "Set-Cookie: ";       
                // 设置cookie
                header += "session_id=123456789abcdef\r\n";
                string blankLine = "\r\n";
                string response = (statusLine + header + blankLine + text);
                write(sockFd, response.c_str(), response.size());
            } else if (n==0) {
                cout << "read done\n";
                break;
            } else {
                cout << "read error!\n";
                break;
            } 
        }   
        close(sockFd);
    }

    // 读文件
    string readFromFile(string path)
    {
        std::ifstream file(path, std::ios::binary);     // 二进制方式打开
        if(!file)  {
            log(FATAL, "readFromHtml() open error!\n");
            return "";
        }

        file.seekg(0, std::ios::end);
        std::size_t fileSize = file.tellg();             // 得到文件的大小
        file.seekg(0);
        std::string content(fileSize, '0');              // 给content先分配大小
        file.read((char*)content.c_str(), fileSize);     // 直接读fileSize大小
        file.close();
        return content;
    }

    // 通过哈希表来获取url后缀中的文件格式的conteType
    string getContentTypeValue(const string& suffix)
    {
        auto pos = _contentType.find(suffix);
        return (pos == _contentType.end()) ? _contentType[".html"] : _contentType[suffix];      // 默认返回html
    }
private:
    Sock _sock;
    uint16_t _port;
    unordered_map<string, string> _contentType;     // 需要在构造函数初始化
};
